home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / video / zapem-0.000 / zapem-0 / zapem / gif.cc < prev    next >
C/C++ Source or Header  |  1995-06-03  |  10KB  |  380 lines

  1. /*
  2.  * Gif C++ class by Alex Hornby - based strongly on...
  3.  *
  4.  * xgifload.c  -  based strongly on...
  5.  *
  6.  * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
  7.  *
  8.  * Copyright (c) 1988, 1989 by Patrick J. Naughton
  9.  *
  10.  * Author: Patrick J. Naughton
  11.  * naughton@wind.sun.com
  12.  *
  13.  * Permission to use, copy, modify, and distribute this software and its
  14.  * documentation for any purpose and without fee is hereby granted,
  15.  * provided that the above copyright notice appear in all copies and that
  16.  * both that copyright notice and this permission notice appear in
  17.  * supporting documentation.
  18.  *
  19.  * This file is provided AS IS with no warranties of any kind.  The author
  20.  * shall have no liability with respect to the infringement of copyrights,
  21.  * trade secrets or any patents by this file or any part thereof.  In no
  22.  * event will the author be liable for any lost revenue or profits or
  23.  * other special, indirect and consequential damages.
  24.  *
  25.  */
  26. extern "C" {
  27. #include <string.h>
  28. #include <vga.h>
  29. }
  30.  
  31. #include <iostream.h>
  32. #include "btypes.h"
  33. #include "palette.h"
  34. #include "gif.h"
  35.  
  36. char * (Gif::id) ="GIF87a";
  37.  
  38. void 
  39. Gif::SetPalette(Palette& p)
  40. {
  41. int i=0;
  42.     
  43.     for(i=0;i<256;i++)
  44.     {
  45.     if(p.getAlloc(i))
  46.         p.allocate(i,Red[i]>>2,Green[i]>>2,Blue[i]>>2);
  47.     }
  48. }
  49.  
  50. void Gif::Load(const char *fname)
  51. {
  52.     if (strcmp(fname,"-")==0) { fp = stdin;  fname = "<stdin>"; }
  53.                          else fp = fopen(fname,"rb");
  54.     Load(fp);
  55. }
  56.  
  57. /*****************************/
  58. void Gif::Load(FILE *fileptr)
  59. /*****************************/
  60. {
  61.     int            filesize;
  62.     register byte  ch, ch1;
  63.     register byte *ptr, *ptr1;
  64.     register int   i;
  65.     
  66.     fp=fileptr;
  67.     if (!fp) FatalError("Gif file not found.");
  68.  
  69.     /* find the size of the file */
  70.     fseek(fp, 0L, 2);
  71.     filesize = ftell(fp);
  72.     fseek(fp, 0L, 0);
  73.  
  74.     if (!(ptr = RawGIF = (byte *) malloc(filesize)))
  75.     FatalError("not enough memory to read gif file");
  76.  
  77.     if (!(Raster = (byte *) malloc(filesize)))
  78.     FatalError("not enough memory to read gif file");
  79.  
  80.     if (fread(ptr, filesize, 1, fp) != 1)
  81.     FatalError("GIF data read failed");
  82.  
  83.     if (strncmp(ptr, id, 6))
  84.     FatalError("not a GIF file");
  85.  
  86.     ptr += 6;
  87.  
  88. /* Get variables from the GIF screen descriptor */
  89.  
  90.     ch = NEXTBYTE;
  91.     RWidth = ch + 0x100 * NEXTBYTE;    /* screen dimensions... not used. */
  92.     ch = NEXTBYTE;
  93.     RHeight = ch + 0x100 * NEXTBYTE;
  94.  
  95.     if (Verbose)
  96.     fprintf(stderr, "screen dims: %dx%d.\n", RWidth, RHeight);
  97.  
  98.     ch = NEXTBYTE;
  99.     HasColormap = ((ch & COLORMAPMASK) ? True : False);
  100.  
  101.     BitsPerPixel = (ch & 7) + 1;
  102.     numcols = ColorMapSize = 1 << BitsPerPixel;
  103.     BitMask = ColorMapSize - 1;
  104.  
  105.     Background = NEXTBYTE;        /* background color... not used. */
  106.  
  107.     if (NEXTBYTE)        /* supposed to be NULL */
  108.     FatalError("corrupt GIF file (bad screen descriptor)");
  109.  
  110.  
  111. /* Read in global colormap. */
  112.  
  113.     if (HasColormap) {
  114.     if (Verbose)
  115.         fprintf(stderr, "%s is %dx%d, %d bits per pixel, (%d colors).\n",
  116.         "<filename>", Width,Height,BitsPerPixel, ColorMapSize);
  117.     for (i = 0; i < ColorMapSize; i++) {
  118.         Red[i] = NEXTBYTE;
  119.         Green[i] = NEXTBYTE;
  120.         Blue[i] = NEXTBYTE;
  121.             used[i] = 0;
  122.         }
  123.         numused = 0;
  124.  
  125.         }
  126.  
  127.     else {  /* no colormap in GIF file */
  128.         fprintf(stderr,"warning!  no colortable in this file.  Winging it.\n");
  129.         if (!numcols) numcols=256;
  130.         }
  131.  
  132. /* Check for image seperator */
  133.  
  134.     if (NEXTBYTE != IMAGESEP)
  135.     FatalError("corrupt GIF file (no image separator)");
  136.  
  137. /* Now read in values from the image descriptor */
  138.  
  139.     ch = NEXTBYTE;
  140.     LeftOfs = ch + 0x100 * NEXTBYTE;
  141.     ch = NEXTBYTE;
  142.     TopOfs = ch + 0x100 * NEXTBYTE;
  143.     ch = NEXTBYTE;
  144.     Width = ch + 0x100 * NEXTBYTE;
  145.     ch = NEXTBYTE;
  146.     Height = ch + 0x100 * NEXTBYTE;
  147.     Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
  148.  
  149.     if (Verbose)
  150.     fprintf(stderr, "Reading a %d by %d %sinterlaced image...",
  151.         Width, Height, (Interlace) ? "" : "non-");
  152.  
  153. /* Note that I ignore the possible existence of a local color map.
  154.  * I'm told there aren't many files around that use them, and the spec
  155.  * says it's defined for future use.  This could lead to an error
  156.  * reading some files. 
  157.  */
  158.  
  159. /* Start reading the raster data. First we get the intial code size
  160.  * and compute decompressor constant values, based on this code size.
  161.  */
  162.  
  163.     CodeSize = NEXTBYTE;
  164.     ClearCode = (1 << CodeSize);
  165.     EOFCode = ClearCode + 1;
  166.     FreeCode = FirstFree = ClearCode + 2;
  167.  
  168. /* The GIF spec has it that the code size is the code size used to
  169.  * compute the above values is the code size given in the file, but the
  170.  * code size used in compression/decompression is the code size given in
  171.  * the file plus one. (thus the ++).
  172.  */
  173.  
  174.     CodeSize++;
  175.     InitCodeSize = CodeSize;
  176.     MaxCode = (1 << CodeSize);
  177.     ReadMask = MaxCode - 1;
  178.  
  179. /* Read the raster data.  Here we just transpose it from the GIF array
  180.  * to the Raster array, turning it from a series of blocks into one long
  181.  * data stream, which makes life much easier for ReadCode().
  182.  */
  183.  
  184.     ptr1 = Raster;
  185.     do {
  186.     ch = ch1 = NEXTBYTE;
  187.     while (ch--) *ptr1++ = NEXTBYTE;
  188.     if ((Raster - ptr1) > filesize)
  189.         FatalError("corrupt GIF file (unblock)");
  190.     } while(ch1);
  191.  
  192.     free(RawGIF);        /* We're done with the raw data now... */
  193.  
  194.     if (Verbose) {
  195.     fprintf(stderr, "done.\n");
  196.     fprintf(stderr, "Decompressing...");
  197.     }
  198.  
  199.  
  200. /* Allocate the X Image */
  201.     Image = (byte *) malloc(Width*Height);
  202.     if (!Image) FatalError("not enough memory for XImage");
  203. /*
  204.     theImage = XCreateImage(theDisp,theVisual,8,ZPixmap,0,Image,
  205.                          Width,Height,8,Width);
  206.     if (!theImage) FatalError("unable to create XImage");
  207. */
  208.     BytesPerScanline = Width;
  209.  
  210.  
  211. /* Decompress the file, continuing until you see the GIF EOF code.
  212.  * One obvious enhancement is to add checking for corrupt files here.
  213.  */
  214.  
  215.     Code = ReadCode();
  216.     while (Code != EOFCode) {
  217.  
  218. /* Clear code sets everything back to its initial value, then reads the
  219.  * immediately subsequent code as uncompressed data.
  220.  */
  221.  
  222.     if (Code == ClearCode) {
  223.         CodeSize = InitCodeSize;
  224.         MaxCode = (1 << CodeSize);
  225.         ReadMask = MaxCode - 1;
  226.         FreeCode = FirstFree;
  227.         CurCode = OldCode = Code = ReadCode();
  228.         FinChar = CurCode & BitMask;
  229.         AddToPixel(FinChar);
  230.     }
  231.     else {
  232.  
  233. /* If not a clear code, then must be data: save same as CurCode and InCode */
  234.  
  235.         CurCode = InCode = Code;
  236.  
  237. /* If greater or equal to FreeCode, not in the hash table yet;
  238.  * repeat the last character decoded
  239.  */
  240.  
  241.         if (CurCode >= FreeCode) {
  242.         CurCode = OldCode;
  243.         OutCode[OutCount++] = FinChar;
  244.         }
  245.  
  246. /* Unless this code is raw data, pursue the chain pointed to by CurCode
  247.  * through the hash table to its end; each code in the chain puts its
  248.  * associated output code on the output queue.
  249.  */
  250.  
  251.         while (CurCode > BitMask) {
  252.         if (OutCount > 1024) {
  253.             fprintf(stderr,"\nCorrupt GIF file (OutCount)!\n");
  254.                     exit(-1);  /* calling 'exit(-1)' dumps core, so I don't */
  255.                     }
  256.         OutCode[OutCount++] = Suffix[CurCode];
  257.         CurCode = Prefix[CurCode];
  258.         }
  259.  
  260. /* The last code in the chain is treated as raw data. */
  261.  
  262.         FinChar = CurCode & BitMask;
  263.         OutCode[OutCount++] = FinChar;
  264.  
  265. /* Now we put the data out to the Output routine.
  266.  * It's been stacked LIFO, so deal with it that way...
  267.  */
  268.  
  269.         for (i = OutCount - 1; i >= 0; i--)
  270.         AddToPixel(OutCode[i]);
  271.         OutCount = 0;
  272.  
  273. /* Build the hash table on-the-fly. No table is stored in the file. */
  274.  
  275.         Prefix[FreeCode] = OldCode;
  276.         Suffix[FreeCode] = FinChar;
  277.         OldCode = InCode;
  278.  
  279. /* Point to the next slot in the table.  If we exceed the current
  280.  * MaxCode value, increment the code size unless it's already 12.  If it
  281.  * is, do nothing: the next code decompressed better be CLEAR
  282.  */
  283.  
  284.         FreeCode++;
  285.         if (FreeCode >= MaxCode) {
  286.         if (CodeSize < 12) {
  287.             CodeSize++;
  288.             MaxCode *= 2;
  289.             ReadMask = (1 << CodeSize) - 1;
  290.         }
  291.         }
  292.     }
  293.     Code = ReadCode();
  294.     }
  295.  
  296.     free(Raster);
  297.  
  298.     if (Verbose)
  299.     fprintf(stderr, "done.\n");
  300.    
  301.     if (fp != stdin)
  302.     fclose(fp);
  303.  
  304. }
  305.  
  306.  
  307. /* Fetch the next code from the raster data stream.  The codes can be
  308.  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
  309.  * maintain our location in the Raster array as a BIT Offset.  We compute
  310.  * the byte Offset into the raster array by dividing this by 8, pick up
  311.  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
  312.  * bring the desired code to the bottom, then mask it off and return it. 
  313.  */
  314. int Gif::ReadCode(void)
  315. {
  316. int RawCode, ByteOffset;
  317.  
  318.     ByteOffset = BitOffset / 8;
  319.     RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
  320.     if (CodeSize >= 8)
  321.     RawCode += (0x10000 * Raster[ByteOffset + 2]);
  322.     RawCode >>= (BitOffset % 8);
  323.     BitOffset += CodeSize;
  324.     return(RawCode & ReadMask);
  325. }
  326.  
  327.  
  328. void Gif::AddToPixel(byte Index)
  329. {
  330.     if (YC<Height)
  331.         *(Image + YC * BytesPerScanline + XC) = Index;
  332.  
  333.     if (!used[Index]) { used[Index]=1;  numused++; }
  334.  
  335. /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
  336.  
  337.     if (++XC == Width) {
  338.  
  339. /* If a non-interlaced picture, just increment YC to the next scan line. 
  340.  * If it's interlaced, deal with the interlace as described in the GIF
  341.  * spec.  Put the decoded scan line out to the screen if we haven't gone
  342.  * past the bottom of it
  343.  */
  344.  
  345.     XC = 0;
  346.     if (!Interlace) YC++;
  347.     else {
  348.         switch (Pass) {
  349.         case 0:
  350.             YC += 8;
  351.             if (YC >= Height) {
  352.             Pass++;
  353.             YC = 4;
  354.             }
  355.         break;
  356.         case 1:
  357.             YC += 8;
  358.             if (YC >= Height) {
  359.             Pass++;
  360.             YC = 2;
  361.             }
  362.         break;
  363.         case 2:
  364.             YC += 4;
  365.             if (YC >= Height) {
  366.             Pass++;
  367.             YC = 1;
  368.             }
  369.         break;
  370.         case 3:
  371.             YC += 2;
  372.         break;
  373.         default:
  374.         break;
  375.         }
  376.     }
  377.     }
  378. }
  379.  
  380.